package org.meetunexpectedly.service.audit.impl;

import org.meetunexpectedly.config.QiNiuConfig;
import org.meetunexpectedly.constant.AuditStatus;
import org.meetunexpectedly.entity.response.AuditResponse;
import org.meetunexpectedly.entity.task.VideoTask;
import org.meetunexpectedly.entity.video.Video;
import org.meetunexpectedly.mapper.video.VideoMapper;
import org.meetunexpectedly.service.audit.AuditService;
import org.meetunexpectedly.service.audit.ImageAuditService;
import org.meetunexpectedly.service.audit.TextAuditService;
import org.meetunexpectedly.service.audit.VideoAuditService;
import org.meetunexpectedly.service.file.FileService;
import org.meetunexpectedly.service.user.FeedService;
import org.meetunexpectedly.service.user.FollowService;
import org.meetunexpectedly.service.video.InterestPushService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @Description: 视频发布审核
 * @Author: pupil
 * @Date: 2024/08/18 下午 11:31
 */
@Service
public class VideoPublishAuditServiceImpl implements AuditService<VideoTask, VideoTask>, InitializingBean {

    @Autowired
    private VideoAuditService videoAuditService;

    @Autowired
    private TextAuditService textAuditService;

    @Autowired
    private ImageAuditService imageAuditService;

    @Autowired
    private VideoMapper videoMapper;

    @Autowired
    private FileService fileService;

    @Autowired
    private FeedService feedService;

    @Autowired
    private FollowService followService;

    @Autowired
    private InterestPushService interestPushService;

    // 线程池
    protected ThreadPoolExecutor executor;
    // 最大线程数
    private int maximumPoolSize = 8;
    // 存活时间
    private int keepAliveTime = 60;
    // 存活时间单位
    private TimeUnit timeUnit = TimeUnit.SECONDS;
    // 阻塞队列长度
    private int blockingQueueSize = 1000;

    /**
     * 审核功能
     * 用于特权功能
     * 有特权开启新线程进行快审核
     * 没有特权用线程池中的线程进行审核(任务多时是慢审核情况)
     *
     * @param videoTask       视频审核任务
     * @param auditQueueState 审核快慢状态  申请快/慢审核
     * @return
     */
    public VideoTask audit(VideoTask videoTask, Boolean auditQueueState) {
        // 快审核就是开多个线程
        if (auditQueueState) {
            new Thread(() -> {
                audit(videoTask);
            }).start();
        } else {
            audit(videoTask);
        }
        return null;
    }

    /**
     * 进行视频审核任务的处理
     *
     * @param videoTask
     * @return
     */
    @Override
    public VideoTask audit(VideoTask videoTask) {
        // 向线程池中提交任务
        executor.submit(() -> {
            Video video = videoTask.getVideo();
            Video videoResult = new Video();
            BeanUtils.copyProperties(video, videoResult);
            // 避免干扰
            videoResult.setMsg("");
            // 只有视频在新增、修改为公开时候才需要调用审核视频、封面、标题和简介
            // 新增并且时公开状态： 必须审核
            // 修改: 新老状态不一致  老状态是私密，新状态是公开时
            // 需要审核视频、封面、标题和简介
            boolean needAuditVideo = false; // 标记是否需要审核
            // 视频是新增并且公开状态
            if (videoTask.getIsAdd() && videoTask.getNewState() == videoTask.getOldState()) {
                needAuditVideo = true;
            } else if (!videoTask.getIsAdd() && videoTask.getOldState() != videoTask.getNewState() && !videoTask.getNewState()) {
                // 修改的情况下新老状态不一致并且新状态为公开,说明需要更新
                needAuditVideo = true;
            }

            AuditResponse videoAuditResponse = new AuditResponse(AuditStatus.SUCCESS.num, "正常");
            AuditResponse coverAuditResponse = new AuditResponse(AuditStatus.SUCCESS.num, "正常");
            AuditResponse titleAuditResponse = new AuditResponse(AuditStatus.SUCCESS.num, "正常");
            AuditResponse descAuditResponse = new AuditResponse(AuditStatus.SUCCESS.num, "正常");

            if (needAuditVideo) {
                videoAuditResponse = videoAuditService.audit(QiNiuConfig.RealmName + "/" + fileService.getById(video.getUrl()).getFileKey());
                coverAuditResponse = imageAuditService.audit(QiNiuConfig.RealmName + "/" + fileService.getById(video.getCover()).getFileKey());

                // 新增的视频，标题简介都要审核
                if (videoTask.getIsAdd()) {
                    titleAuditResponse = textAuditService.audit(video.getTitle());
                    descAuditResponse = textAuditService.audit(video.getDescription());
                } else {
                    // 不是新增视频，判断新老视频标题简介是否一致
                    Video oldVideo = videoTask.getOldVideo();
                    if (!video.getTitle().equals(oldVideo.getTitle())) {
                        titleAuditResponse = textAuditService.audit(video.getTitle());
                    }
                    if (!video.getDescription().equals(oldVideo.getDescription())) {
                        descAuditResponse = textAuditService.audit(video.getDescription());
                    }
                }
            } else if (videoTask.getNewState()) {
                // 私密状态(true)
                // 从标签库和分类库中删除该视频
                interestPushService.deleteSystemTypeStockIn(videoResult);
                interestPushService.deleteSystemStockIn(videoResult);

                // 删除发件箱以及收件箱
                final Collection<Long> fans = followService.getFans(null, videoResult.getUserId());
                feedService.deleteOutBoxFeed(videoResult.getUserId(), fans, video.getId());
            }

            Integer videoAuditStatus = videoAuditResponse.getAuditStatus();
            Integer coverAuditStatus = coverAuditResponse.getAuditStatus();
            Integer titleAuditStatus = titleAuditResponse.getAuditStatus();
            Integer descAuditStatus = descAuditResponse.getAuditStatus();

            boolean videoFile = videoAuditStatus.equals(AuditStatus.SUCCESS.num);
            boolean coverFile = coverAuditStatus.equals(AuditStatus.SUCCESS.num);
            boolean titleFile = titleAuditStatus.equals(AuditStatus.SUCCESS.num);
            boolean descFile = descAuditStatus.equals(AuditStatus.SUCCESS.num);

            if (videoFile && coverFile && titleFile && descFile) {
                videoResult.setMsg("通过");
                videoResult.setAuditStatus(AuditStatus.SUCCESS.num);
                if (!videoTask.getNewState()) {

                    // 存储到标签库和分类库中，用于兴趣推送
                    interestPushService.pushSystemTypeStockIn(videoResult);
                    interestPushService.pushSystemStockIn(videoResult);

                    // 推入发件箱
                    feedService.putOutBoxFeed(videoResult.getUserId(), videoResult.getId(), videoResult.getGmtCreated().getTime());

                    // 推送内容到在线粉丝中
                    Collection<Long> fansIds = followService.getFans(null, video.getUserId());
                    feedService.putInBoxFeed(videoResult.getId(), fansIds, videoResult.getGmtCreated().getTime());
                }
            } else {
                videoResult.setAuditStatus(AuditStatus.PASS.num);
                if (!videoFile) {
                    videoResult.setMessage("视频有违规行为：" + videoAuditResponse.getMsg());
                }
                if (!coverFile) {
                    videoResult.setMessage("封面有违规行为: " + coverAuditResponse.getMsg());
                }
                if (!titleFile) {
                    videoResult.setMessage("标题有违规行为: " + titleAuditResponse.getMsg());
                }
                if (!descFile) {
                    videoResult.setMessage("简介有违规行为: " + descAuditResponse.getMsg());
                }
            }

            videoMapper.updateById(videoResult);
        });
        return null;
    }

    /**
     * 判断现在快审核还是慢审核
     *
     * @return
     */
    public boolean getAuditQueueState() {
        return executor.getTaskCount() < maximumPoolSize;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        executor = new ThreadPoolExecutor(5, maximumPoolSize, keepAliveTime, timeUnit, new ArrayBlockingQueue<>(blockingQueueSize));
    }

}
